Executive Summary

The National Institute of Health (NIH) National Center for Advancing Translational Sciences (NCATS) collaborated on a study to explore mouse development in the dorsal root ganglia. Five time points were collected throughout development.

For this analysis, Rancho proposes to run Cell Ranger to align, filter, count barcodes, count UMI and aggregate multiple runs of Cell Ranger count if necessary. Rancho will review and troubleshoot the Seurat workflow for all time points and identify the optimal resolution for clustering. There may be a higher than normal number of doublet droplets; therefore, we will run the created Seurat object through DoubletFinder. We will estimate the predicted doublets in the dataset in comparison to the Seurat object without running DoubletFinder. After running DoubletFinder, we will perform differential gene expression analysis using Seurat and over-representation analysis using the Broad Institute’s GSEA program. Lastly, we will run Slingshot to build single-cell trajectories using pseudotime.

Input data

Chromium Single Cell sequencing using the i7 single index plates were provided as 160 individual paired-end FASTQ files. Five distinct samples were indexed according to Table I and sequenced using 4 barcode sequences, which have balanced base composition. Each of these barcodes was sequenced across 4 lanes. (5 samples * 4 barcodes * 4 lanes * 2 ends = 160 files)

Sample sheet

Sample I7_Index_ID Barcodes
082120DRG SI-GA-G1 ATGAATCT,GATCTCAG,CCAGGAGC,TGCTCGTA
101920DRG SI-GA-G9 TAGGACGT,ATCCCACA,GGAATGTC,CCTTGTAG
103020DRG SI-GA-C9 GCGCAGAA,ATCTTACC,TATGGTGT,CGAACCTG
110220DRG SI-GA-D9 AGGAGATG,GATGTGGT,CTACATCC,TCCTCCAA
111220DRG SI-GA-H9 ACACTGTT,CAGGATGG,GGCTGAAC,TTTACCCA

While explicit sample preparation information was not provided, it has been inferred from the sample labeling and publications from the source laboratory (Ahmet Hoke) that these are purified dorsal root ganglia explant samples from healthy mice at 5 time-points across 12-weeks (unknown starting status).

Solution

Processing FASTQ to produce UMI counts

Single cell feature counts for a single library were generated using the following cellranger count script. This was performed by first downloading a current prebuilt reference library for mus musculus mm10 assembly.

wget https://cf.10xgenomics.com/supp/cell-exp/refdata-gex-mm10-2020-A.tar.gz
code/run-cellranger-count.sh

Results from cellrange count quanlity summary metrics indicated that all samples were good quality and suitable for downstream analysis.

Table 1 - Cell Ranger Count Summary Stats

Sample Est. Cell Number Mean Reads / Cell Median Genes / Cell Reads Mapped Confidently to Genome
082120DRG 11,198 53,351 2,290 87.3%
101920DRG 11,926 77,566 2,491 93.3%
103020DRG 9,876 64,663 3,350 92.7%
110220DRG 8,342 62,208 3,275 93.1%
111220DRG 15,515 54,126 2,670 93.2%

Seurat sample preprocessing

In order to facilitate streamlined preprocessing of individual sample each was subject to import, calculation of percent mitochodrial content per cell, application of cutoffs related to umi counts and mito content, scaleing and normalization. These operations were applied using the seurat-processor.Rmd through code/01b-render-all-seurat-processors.R. This allows not only consistent processing settings but also sample-specific logging along with customized diagnostic plots.

Since sequencing operations on each sample are nonstandard, filtering criteria were configured using config.yml. This includes min/max cutoffs for nFeature_RNA and percent.mt in addition to number of umap dimensions for clustering and cluster resolution.

Outputs preprocesing reports can be found at:

data/seurat-preprocesing-reports/
├── filtering-082120DRG.html
├── filtering-101920DRG.html
├── filtering-103020DRG.html
├── filtering-110220DRG.html
└── filtering-111220DRG.html

0 directories, 5 files

Doublet detection

Based on information from the Dr. Hoke’s lab and NCATS, it is possible that experimentalists may have overloaded the chip, potentially producing excessive doublet droplets (droplets with more than one cell). To determine if doublets were problematic in the dataset, we utilized the DoubletFinder package in R.

The DoubletFinder method includes 4 distinct steps:

  1. Generate artificial doublets from existing scRNA-seq data
  2. Pre-process merged real-artificial data
  3. Perform PCA and use the PC distance matrix to find each cell’s proportion of artificial k nearest neighbors (pANN)
  4. Rank order and threshold pANN values according to the expected number of doublets

Following recommended steps from this package, individual samples were imported as Seurat objects, normalized and scaled before applying the DoubleFinder methods. 02-doublet-finder.R was run interactively for all 5 samples in order to optimize pK and nExp. This included a pN-pK parameter sweeps on a 10,000-cell subset of a pre-processed Seurat object. Will use all cells if Seurat object contains less than 10,000 cells. Results are fed into summarizeSweep() and find.pK() functions during optimal pK parameter selection workflow. Parameters tested: pN = 0.05-0.3, pK = 0.0005-0.3

Results from the Doublet Finder algorithm did not successfully identify any likely doublet cells. The analysis was confirmed with two separate approaches: with and without estimation of homotypic doublet cells. Since DoubletFinder is insensitive to homotypic doublets the estimation process is entirely based on estimated frequency within clusters, and highly subject to input parameters. The package authors consider doublet number estimates based on Poisson statistics with and without homotypic doublet proportion adjustment to ‘bookend’ the real detectable doublet rate, however in these cases where we see a range from 0 (without homotypic) through 25% cell count (the value used to estimate homotypic populations) that this package has identified no actual doublets. In response to this finding we are proceeding with this analysis without adjusting for doublet species cells. Full results can be found on individual doublet finder reports.

data/doublet-finder-reports/
├── 082120DRG.html
├── 101920DRG.html
├── 103020DRG.html
├── 110220DRG.html
└── 111220DRG.html

0 directories, 5 files

Main Seurat object processor

After individual samples were ingested, filtered and considered for doublet exclusion they were aggregated into a single seurat object and normalized. This process was implemented as code/01c-merge.R. Processing included the following major steps:

  1. Merge into a single seurat
  2. Score each cell for S and G2M cell cycle effects that are included in the regression/normalization steps. See code/cell-cycle-testing.R and Apr 1, 2021 presentation for details.
  3. NormalizeData, FindVariableFeatures, ScaleData
  4. RunPCA followed by Elbow plot to identify important principal components
  5. RunUMAP follwed by DimPlot
  6. Identify optimal cluster resolution using clustree
  7. Output from this main processing is stored as objects/filtered-merged-umap.RDS

Differential expression

Once an optimal Seurat resolution had been selected (0.03), we ran differential gene expression analysis in Seurat using the FindMarkers function in Seurat. This was performed for each cluster in a cluster-vs-all contrast model. Since a list of targeted genes was not explicitly provided we report the top 20 genes per cluster.

ls data/plots/dex-top-dotplot*
data/plots/dex-top-dotplot_COMBINED.png
data/plots/dex-top-dotplot_cluster-0.png
data/plots/dex-top-dotplot_cluster-1.png
data/plots/dex-top-dotplot_cluster-2.png
data/plots/dex-top-dotplot_cluster-3.png
data/plots/dex-top-dotplot_cluster-4.png
data/plots/dex-top-dotplot_cluster-5.png
data/plots/dex-top-dotplot_cluster-6.png
data/plots/dex-top-dotplot_cluster-7.png
data/plots/dex-top-dotplot_cluster-8.png

General enrichment analysis

We followed-up the DGE analysis with over-representation analysis using msigdb and clusterprofiler in R exploring the GO gene sets and KEGG. This work was defined by the code/06-enrichr.R script and includes msigdb categories “KEGG”, “C5”(Go terms) as well as modules defined for the iPSC cluster profiler tool at NCATs. Results are summarized on the data/table/enriched-sets.tsv

read_tsv("data/tables/enriched-sets.tsv", col_types = cols(
  cluster = col_double(),
  hits = col_double(),
  ID = col_character(),
  Description = col_character(),
  GeneRatio = col_character(),
  BgRatio = col_character(),
  pvalue = col_double(),
  p.adjust = col_double(),
  qvalue = col_double(),
  geneID = col_character(),
  Count = col_double() )) %>% 
  slice(1:10) %>% 
  select(-geneID)
ls data/plots/go*
ls data/plots/kegg*
data/plots/go-NEURO-heatmap.png
data/plots/go-heatmap.png
data/plots/kegg-heatmap.png

Module conversion and scoring

Lastly, to better understand the identity or cell type for each cluster, we ran Seurat’s AddModuleScore function, using NCATS’ list of known cell markers from a previously created iPSC profiler for each cell separation approach. The AddModuleScore calculates the average expression for each cluster subtracted by the aggregated expression of control feature sets. Positive expression levels indicate a higher expression level than random. We will use the expression levels to broadly assign each cluster to potential identities (cell type).

ls data/plots/ipsc*
data/plots/ipsc-feature-plots-1.png
data/plots/ipsc-feature-plots-2.png
data/plots/ipsc-feature-plots-3.png
data/plots/ipsc-feature-plots-4.png
data/plots/ipsc-feature-plots-5.png
data/plots/ipsc-feature-plots-Calponin3.png
data/plots/ipsc-feature-plots-DRG-Markers.png
data/plots/ipsc-feature-plots-S100a8.png
data/plots/ipsc-feature-plots-SGC.png
data/plots/ipsc-feature-plots-cluster0.png
data/plots/ipsc-feature-plots-cluster1.png
data/plots/ipsc-feature-plots-cluster5.png
data/plots/ipsc-module-heatmap-Median.png
data/plots/ipsc-violin-plots-1.png
data/plots/ipsc-violin-plots-2.png
data/plots/ipsc-violin-plots-3.png
data/plots/ipsc-violin-plots-4.png
data/plots/ipsc-violin-plots-5.png
data/plots/ipsc-violin-plots-Calponin3.png
data/plots/ipsc-violin-plots-SGC.png
data/plots/ipsc-violin-plots-cluster0.png
data/plots/ipsc-violin-plots-cluster1.png
data/plots/ipsc-violin-plots-cluster5.png

Trajectory inference

Lastly, we ran Slingshot for single-cell trajectory analysis. The goal of slingshot is to use clusters of cells to uncover global structure and convert these to pseudotime. To accomplish this work we utilized the dynverse set of R-packages in conjunction with provided code from Claire Malley to run Slingshot and extract pseudotime metrics.

This analysis yielded some productive findings across the annotated umap clusters. This roughly followed a trajectory along neuronal precursors (cluster 1), glial/astral/SGC cells (cluster 0, the largest) and splits into several types of maturing nociceptors (cluster 5) and likely alternative developmental neuronal cell types (clusters 3,6)

When an unsupervised pseudotime estimation is plotted on these cells we see a natural progression.

Pseudotype-based differential modeling

After Slingshot was run, we explored temporally expressed genes using the tradeSeq package. For each gene, we fit a general additive model (GAM) using a negative binomial noise distribution to model relationships between gene expression and pseudotime. After running the GAM model, we tested for significant associations between expression and pseudotime using the associationTest.

LS0tCnRpdGxlOiAic2NSTkEtU2VxIEFuYWx5c2lzIG9mIE1vdXNlIERldmVsb3BtZW50IgphdXRob3I6ICJEYW4gUm96ZWxsZSIKZGF0ZTogIjQvMi8yMDIxIgpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sKZWRpdG9yX29wdGlvbnM6IAogIGNodW5rX291dHB1dF90eXBlOiBpbmxpbmUKLS0tCgojIEV4ZWN1dGl2ZSBTdW1tYXJ5IAoKVGhlIE5hdGlvbmFsIEluc3RpdHV0ZSBvZiBIZWFsdGggKE5JSCkgTmF0aW9uYWwgQ2VudGVyIGZvciBBZHZhbmNpbmcgVHJhbnNsYXRpb25hbCBTY2llbmNlcyAoTkNBVFMpIGNvbGxhYm9yYXRlZCBvbiBhIHN0dWR5IHRvIGV4cGxvcmUgbW91c2UgZGV2ZWxvcG1lbnQgaW4gdGhlIGRvcnNhbCByb290IGdhbmdsaWEuIEZpdmUgdGltZSBwb2ludHMgd2VyZSBjb2xsZWN0ZWQgdGhyb3VnaG91dCBkZXZlbG9wbWVudC4gICAKCkZvciB0aGlzIGFuYWx5c2lzLCBSYW5jaG8gcHJvcG9zZXMgdG8gcnVuIENlbGwgUmFuZ2VyIHRvIGFsaWduLCBmaWx0ZXIsIGNvdW50IGJhcmNvZGVzLCBjb3VudCBVTUkgYW5kIGFnZ3JlZ2F0ZSBtdWx0aXBsZSBydW5zIG9mIENlbGwgUmFuZ2VyIGNvdW50IGlmIG5lY2Vzc2FyeS4gUmFuY2hvIHdpbGwgcmV2aWV3IGFuZCB0cm91Ymxlc2hvb3QgdGhlIFNldXJhdCB3b3JrZmxvdyBmb3IgYWxsIHRpbWUgcG9pbnRzIGFuZCBpZGVudGlmeSB0aGUgb3B0aW1hbCByZXNvbHV0aW9uIGZvciBjbHVzdGVyaW5nLiBUaGVyZSBtYXkgYmUgYSBoaWdoZXIgdGhhbiBub3JtYWwgbnVtYmVyIG9mIGRvdWJsZXQgZHJvcGxldHM7IHRoZXJlZm9yZSwgd2Ugd2lsbCBydW4gdGhlIGNyZWF0ZWQgU2V1cmF0IG9iamVjdCB0aHJvdWdoIERvdWJsZXRGaW5kZXIuIFdlIHdpbGwgZXN0aW1hdGUgdGhlIHByZWRpY3RlZCBkb3VibGV0cyBpbiB0aGUgZGF0YXNldCBpbiBjb21wYXJpc29uIHRvIHRoZSBTZXVyYXQgb2JqZWN0IHdpdGhvdXQgcnVubmluZyBEb3VibGV0RmluZGVyLiBBZnRlciBydW5uaW5nIERvdWJsZXRGaW5kZXIsIHdlIHdpbGwgcGVyZm9ybSBkaWZmZXJlbnRpYWwgZ2VuZSBleHByZXNzaW9uIGFuYWx5c2lzIHVzaW5nIFNldXJhdCBhbmQgb3Zlci1yZXByZXNlbnRhdGlvbiBhbmFseXNpcyB1c2luZyB0aGUgQnJvYWQgSW5zdGl0dXRl4oCZcyBHU0VBIHByb2dyYW0uIExhc3RseSwgd2Ugd2lsbCBydW4gU2xpbmdzaG90IHRvIGJ1aWxkIHNpbmdsZS1jZWxsIHRyYWplY3RvcmllcyB1c2luZyBwc2V1ZG90aW1lLiAgCgojIyBJbnB1dCBkYXRhIAoKQ2hyb21pdW0gU2luZ2xlIENlbGwgc2VxdWVuY2luZyB1c2luZyB0aGUgaTcgc2luZ2xlIGluZGV4IHBsYXRlcyB3ZXJlIHByb3ZpZGVkIGFzIDE2MCBpbmRpdmlkdWFsIHBhaXJlZC1lbmQgRkFTVFEgZmlsZXMuIEZpdmUgZGlzdGluY3Qgc2FtcGxlcyB3ZXJlIGluZGV4ZWQgYWNjb3JkaW5nIHRvIFRhYmxlIEkgYW5kIHNlcXVlbmNlZCB1c2luZyA0IGJhcmNvZGUgc2VxdWVuY2VzLCB3aGljaCBoYXZlIGJhbGFuY2VkIGJhc2UgY29tcG9zaXRpb24uIEVhY2ggb2YgdGhlc2UgYmFyY29kZXMgd2FzIHNlcXVlbmNlZCBhY3Jvc3MgNCBsYW5lcy4gKDUgc2FtcGxlcyAqIDQgYmFyY29kZXMgKiA0IGxhbmVzICogMiBlbmRzID0gMTYwIGZpbGVzKQoKIyMjIyAqKlNhbXBsZSBzaGVldCoqCgpTYW1wbGUgICAgfEk3X0luZGV4X0lECXxCYXJjb2Rlcwo6LS0tLS0tLS0tIHwgOi0tLS0tLS0tLQl8IDotLS0tLS0tLQowODIxMjBEUkcgfCBTSS1HQS1HMQl8IEFUR0FBVENULEdBVENUQ0FHLENDQUdHQUdDLFRHQ1RDR1RBCjEwMTkyMERSRyB8IFNJLUdBLUc5CXwgVEFHR0FDR1QsQVRDQ0NBQ0EsR0dBQVRHVEMsQ0NUVEdUQUcKMTAzMDIwRFJHIHwgU0ktR0EtQzkJfCBHQ0dDQUdBQSxBVENUVEFDQyxUQVRHR1RHVCxDR0FBQ0NURwoxMTAyMjBEUkcgfCBTSS1HQS1EOQl8IEFHR0FHQVRHLEdBVEdUR0dULENUQUNBVENDLFRDQ1RDQ0FBCjExMTIyMERSRyB8IFNJLUdBLUg5CXwgQUNBQ1RHVFQsQ0FHR0FUR0csR0dDVEdBQUMsVFRUQUNDQ0EKCldoaWxlIGV4cGxpY2l0IHNhbXBsZSBwcmVwYXJhdGlvbiBpbmZvcm1hdGlvbiB3YXMgbm90IHByb3ZpZGVkLCBpdCBoYXMgYmVlbiBpbmZlcnJlZCBmcm9tIHRoZSBzYW1wbGUgbGFiZWxpbmcgYW5kIHB1YmxpY2F0aW9ucyBmcm9tIHRoZSBzb3VyY2UgbGFib3JhdG9yeSAoQWhtZXQgSG9rZSkgdGhhdCB0aGVzZSBhcmUgcHVyaWZpZWQgZG9yc2FsIHJvb3QgZ2FuZ2xpYSBleHBsYW50IHNhbXBsZXMgZnJvbSBoZWFsdGh5IG1pY2UgYXQgNSB0aW1lLXBvaW50cyBhY3Jvc3MgMTItd2Vla3MgKHVua25vd24gc3RhcnRpbmcgc3RhdHVzKS4KCiMgU29sdXRpb24KCiMjIFByb2Nlc3NpbmcgRkFTVFEgdG8gcHJvZHVjZSBVTUkgY291bnRzCgpTaW5nbGUgY2VsbCBmZWF0dXJlIGNvdW50cyBmb3IgYSBzaW5nbGUgbGlicmFyeSB3ZXJlIGdlbmVyYXRlZCB1c2luZyB0aGUgZm9sbG93aW5nIGNlbGxyYW5nZXIgY291bnQgc2NyaXB0LiBUaGlzIHdhcyBwZXJmb3JtZWQgYnkgZmlyc3QgZG93bmxvYWRpbmcgYSBjdXJyZW50IHByZWJ1aWx0IHJlZmVyZW5jZSBsaWJyYXJ5IGZvciBbKm11cyBtdXNjdWx1cyogbW0xMF0oaHR0cHM6Ly9zdXBwb3J0LjEweGdlbm9taWNzLmNvbS9zaW5nbGUtY2VsbC1nZW5lLWV4cHJlc3Npb24vc29mdHdhcmUvZG93bmxvYWRzL2xhdGVzdCkgYXNzZW1ibHkuCgpgYGAKd2dldCBodHRwczovL2NmLjEweGdlbm9taWNzLmNvbS9zdXBwL2NlbGwtZXhwL3JlZmRhdGEtZ2V4LW1tMTAtMjAyMC1BLnRhci5negpjb2RlL3J1bi1jZWxscmFuZ2VyLWNvdW50LnNoCmBgYAoKUmVzdWx0cyBmcm9tIGNlbGxyYW5nZSBjb3VudCBxdWFubGl0eSBzdW1tYXJ5IG1ldHJpY3MgaW5kaWNhdGVkIHRoYXQgYWxsIHNhbXBsZXMgd2VyZSBnb29kIHF1YWxpdHkgYW5kIHN1aXRhYmxlIGZvciBkb3duc3RyZWFtIGFuYWx5c2lzLgoKIyMjIyAqKlRhYmxlIDEgLSBDZWxsIFJhbmdlciBDb3VudCBTdW1tYXJ5IFN0YXRzKioKClNhbXBsZSAgICB8RXN0LiBDZWxsIE51bWJlciB8TWVhbiBSZWFkcyAvIENlbGwgICAgfE1lZGlhbiBHZW5lcyAvIENlbGwgICB8UmVhZHMgTWFwcGVkIENvbmZpZGVudGx5IHRvIEdlbm9tZSAgICAgICAgIAo6LS0tLS0tLS0tfDotLS0tLS0tLS0gICAgICAgfDotLS0tLS0tLS0gICAgICAgICAgIHw6LS0tLS0tLS0tLS0tLS0tLSAgICAgfDotLS0tICAgICAgICAgICAgCjA4MjEyMERSRyB8IDExLDE5OCAgICAgICAgICB8IDUzLDM1MSAgICAgICAgICAgICAgfDIsMjkwICAgICAgICAgICAgICAgICB8IDg3LjMlCjEwMTkyMERSRyB8IDExLDkyNiAgICAgICAgICB8IDc3LDU2NiAgICAgICAgICAgICAgfDIsNDkxICAgICAgICAgICAgICAgICB8IDkzLjMlCjEwMzAyMERSRyB8IDksODc2ICAgICAgICAgICB8IDY0LDY2MyAgICAgICAgICAgICAgfDMsMzUwICAgICAgICAgICAgICAgICB8IDkyLjclCjExMDIyMERSRyB8IDgsMzQyICAgICAgICAgICB8IDYyLDIwOCAgICAgICAgICAgICAgfDMsMjc1ICAgICAgICAgICAgICAgICB8IDkzLjElCjExMTIyMERSRyB8IDE1LDUxNSAgICAgICAgICB8IDU0LDEyNiAgICAgICAgICAgICAgfDIsNjcwICAgICAgICAgICAgICAgICB8IDkzLjIlCgojIyBTZXVyYXQgc2FtcGxlIHByZXByb2Nlc3NpbmcKCkluIG9yZGVyIHRvIGZhY2lsaXRhdGUgc3RyZWFtbGluZWQgcHJlcHJvY2Vzc2luZyBvZiBpbmRpdmlkdWFsIHNhbXBsZSBlYWNoIHdhcyBzdWJqZWN0IHRvIGltcG9ydCwgY2FsY3VsYXRpb24gb2YgcGVyY2VudCBtaXRvY2hvZHJpYWwgY29udGVudCBwZXIgY2VsbCwgYXBwbGljYXRpb24gb2YgY3V0b2ZmcyByZWxhdGVkIHRvIHVtaSBjb3VudHMgYW5kIG1pdG8gY29udGVudCwgc2NhbGVpbmcgYW5kIG5vcm1hbGl6YXRpb24uIFRoZXNlIG9wZXJhdGlvbnMgd2VyZSBhcHBsaWVkIHVzaW5nIHRoZSBgYGBzZXVyYXQtcHJvY2Vzc29yLlJtZGBgYCB0aHJvdWdoIGBgYGNvZGUvMDFiLXJlbmRlci1hbGwtc2V1cmF0LXByb2Nlc3NvcnMuUmBgYC4gVGhpcyBhbGxvd3Mgbm90IG9ubHkgY29uc2lzdGVudCBwcm9jZXNzaW5nIHNldHRpbmdzIGJ1dCBhbHNvIHNhbXBsZS1zcGVjaWZpYyBsb2dnaW5nIGFsb25nIHdpdGggY3VzdG9taXplZCBkaWFnbm9zdGljIHBsb3RzLiAKClNpbmNlIHNlcXVlbmNpbmcgb3BlcmF0aW9ucyBvbiBlYWNoIHNhbXBsZSBhcmUgbm9uc3RhbmRhcmQsIGZpbHRlcmluZyBjcml0ZXJpYSB3ZXJlIGNvbmZpZ3VyZWQgdXNpbmcgYGBgY29uZmlnLnltbGBgYC4gVGhpcyBpbmNsdWRlcyBtaW4vbWF4IGN1dG9mZnMgZm9yIG5GZWF0dXJlX1JOQSBhbmQgcGVyY2VudC5tdCBpbiBhZGRpdGlvbiB0byBudW1iZXIgb2YgdW1hcCBkaW1lbnNpb25zIGZvciBjbHVzdGVyaW5nIGFuZCBjbHVzdGVyIHJlc29sdXRpb24uCgpPdXRwdXRzIHByZXByb2Nlc2luZyByZXBvcnRzIGNhbiBiZSBmb3VuZCBhdDoKCmBgYHtiYXNoIGVjaG89RkFMU0V9CnRyZWUgZGF0YS9zZXVyYXQtcHJlcHJvY2VzaW5nLXJlcG9ydHMvCmBgYAoKIyMgRG91YmxldCBkZXRlY3Rpb24KCkJhc2VkIG9uIGluZm9ybWF0aW9uIGZyb20gdGhlIERyLiBIb2tl4oCZcyBsYWIgYW5kIE5DQVRTLCBpdCBpcyBwb3NzaWJsZSB0aGF0IGV4cGVyaW1lbnRhbGlzdHMgbWF5IGhhdmUgb3ZlcmxvYWRlZCB0aGUgY2hpcCwgcG90ZW50aWFsbHkgcHJvZHVjaW5nIGV4Y2Vzc2l2ZSBkb3VibGV0IGRyb3BsZXRzIChkcm9wbGV0cyB3aXRoIG1vcmUgdGhhbiBvbmUgY2VsbCkuIFRvIGRldGVybWluZSBpZiBkb3VibGV0cyB3ZXJlIHByb2JsZW1hdGljIGluIHRoZSBkYXRhc2V0LCB3ZSB1dGlsaXplZCB0aGUgW0RvdWJsZXRGaW5kZXJdKGh0dHBzOi8vZ2l0aHViLmNvbS9jaHJpcy1tY2dpbm5pcy11Y3NmL0RvdWJsZXRGaW5kZXIpIHBhY2thZ2UgaW4gUi4gCgpUaGUgRG91YmxldEZpbmRlciBtZXRob2QgaW5jbHVkZXMgNCBkaXN0aW5jdCBzdGVwczoKCjEuIEdlbmVyYXRlIGFydGlmaWNpYWwgZG91YmxldHMgZnJvbSBleGlzdGluZyBzY1JOQS1zZXEgZGF0YQoyLiBQcmUtcHJvY2VzcyBtZXJnZWQgcmVhbC1hcnRpZmljaWFsIGRhdGEKMy4gUGVyZm9ybSBQQ0EgYW5kIHVzZSB0aGUgUEMgZGlzdGFuY2UgbWF0cml4IHRvIGZpbmQgZWFjaCBjZWxsJ3MgcHJvcG9ydGlvbiBvZiBhcnRpZmljaWFsIGsgbmVhcmVzdCBuZWlnaGJvcnMgKHBBTk4pCjQuIFJhbmsgb3JkZXIgYW5kIHRocmVzaG9sZCBwQU5OIHZhbHVlcyBhY2NvcmRpbmcgdG8gdGhlIGV4cGVjdGVkIG51bWJlciBvZiBkb3VibGV0cwoKRm9sbG93aW5nIHJlY29tbWVuZGVkIHN0ZXBzIGZyb20gdGhpcyBwYWNrYWdlLCBpbmRpdmlkdWFsIHNhbXBsZXMgd2VyZSBpbXBvcnRlZCBhcyBTZXVyYXQgb2JqZWN0cywgbm9ybWFsaXplZCBhbmQgc2NhbGVkIGJlZm9yZSBhcHBseWluZyB0aGUgRG91YmxlRmluZGVyIG1ldGhvZHMuIGBgYDAyLWRvdWJsZXQtZmluZGVyLlJgYGAgd2FzIHJ1biBpbnRlcmFjdGl2ZWx5IGZvciBhbGwgNSBzYW1wbGVzIGluIG9yZGVyIHRvIG9wdGltaXplIHBLIGFuZCBuRXhwLiBUaGlzIGluY2x1ZGVkIGEgcE4tcEsgcGFyYW1ldGVyIHN3ZWVwcyBvbiBhIDEwLDAwMC1jZWxsIHN1YnNldCBvZiBhIHByZS1wcm9jZXNzZWQgU2V1cmF0IG9iamVjdC4gV2lsbCB1c2UgYWxsIGNlbGxzIGlmIFNldXJhdCBvYmplY3QgY29udGFpbnMgbGVzcyB0aGFuIDEwLDAwMCBjZWxscy4gUmVzdWx0cyBhcmUgZmVkIGludG8gYGBgc3VtbWFyaXplU3dlZXAoKWBgYCBhbmQgYGBgZmluZC5wSygpYGBgIGZ1bmN0aW9ucyBkdXJpbmcgb3B0aW1hbCBwSyBwYXJhbWV0ZXIgc2VsZWN0aW9uIHdvcmtmbG93LiBQYXJhbWV0ZXJzIHRlc3RlZDogcE4gPSAwLjA1LTAuMywgcEsgPSAwLjAwMDUtMC4zCgoqKlJlc3VsdHMqKiBmcm9tIHRoZSBEb3VibGV0IEZpbmRlciBhbGdvcml0aG0gZGlkIG5vdCBzdWNjZXNzZnVsbHkgaWRlbnRpZnkgYW55IGxpa2VseSBkb3VibGV0IGNlbGxzLiBUaGUgYW5hbHlzaXMgd2FzIGNvbmZpcm1lZCB3aXRoIHR3byBzZXBhcmF0ZSBhcHByb2FjaGVzOiB3aXRoIGFuZCB3aXRob3V0IGVzdGltYXRpb24gb2YgaG9tb3R5cGljIGRvdWJsZXQgY2VsbHMuIFNpbmNlIERvdWJsZXRGaW5kZXIgaXMgaW5zZW5zaXRpdmUgdG8gaG9tb3R5cGljIGRvdWJsZXRzIHRoZSBlc3RpbWF0aW9uIHByb2Nlc3MgaXMgZW50aXJlbHkgYmFzZWQgb24gZXN0aW1hdGVkIGZyZXF1ZW5jeSB3aXRoaW4gY2x1c3RlcnMsIGFuZCBoaWdobHkgc3ViamVjdCB0byBpbnB1dCBwYXJhbWV0ZXJzLiBUaGUgcGFja2FnZSBhdXRob3JzIGNvbnNpZGVyIGRvdWJsZXQgbnVtYmVyIGVzdGltYXRlcyBiYXNlZCBvbiBQb2lzc29uIHN0YXRpc3RpY3Mgd2l0aCBhbmQgd2l0aG91dCBob21vdHlwaWMgZG91YmxldCBwcm9wb3J0aW9uIGFkanVzdG1lbnQgdG8gJ2Jvb2tlbmQnIHRoZSByZWFsIGRldGVjdGFibGUgZG91YmxldCByYXRlLCBob3dldmVyIGluIHRoZXNlIGNhc2VzIHdoZXJlIHdlIHNlZSBhIHJhbmdlIGZyb20gMCAod2l0aG91dCBob21vdHlwaWMpIHRocm91Z2ggMjUlIGNlbGwgY291bnQgKHRoZSB2YWx1ZSB1c2VkIHRvIGVzdGltYXRlIGhvbW90eXBpYyBwb3B1bGF0aW9ucykgdGhhdCB0aGlzIHBhY2thZ2UgaGFzIGlkZW50aWZpZWQgbm8gYWN0dWFsIGRvdWJsZXRzLiBJbiByZXNwb25zZSB0byB0aGlzIGZpbmRpbmcgd2UgYXJlIHByb2NlZWRpbmcgd2l0aCB0aGlzIGFuYWx5c2lzIHdpdGhvdXQgYWRqdXN0aW5nIGZvciBkb3VibGV0IHNwZWNpZXMgY2VsbHMuIEZ1bGwgcmVzdWx0cyBjYW4gYmUgZm91bmQgb24gaW5kaXZpZHVhbCBkb3VibGV0IGZpbmRlciByZXBvcnRzLgoKYGBge2Jhc2ggZWNobz1GQUxTRX0KdHJlZSBkYXRhL2RvdWJsZXQtZmluZGVyLXJlcG9ydHMvCmBgYAoKIyMgTWFpbiBTZXVyYXQgb2JqZWN0IHByb2Nlc3NvcgoKQWZ0ZXIgaW5kaXZpZHVhbCBzYW1wbGVzIHdlcmUgaW5nZXN0ZWQsIGZpbHRlcmVkIGFuZCBjb25zaWRlcmVkIGZvciBkb3VibGV0IGV4Y2x1c2lvbiB0aGV5IHdlcmUgYWdncmVnYXRlZCBpbnRvIGEgc2luZ2xlIHNldXJhdCBvYmplY3QgYW5kIG5vcm1hbGl6ZWQuIFRoaXMgcHJvY2VzcyB3YXMgaW1wbGVtZW50ZWQgYXMgYGBgY29kZS8wMWMtbWVyZ2UuUmBgYC4gUHJvY2Vzc2luZyBpbmNsdWRlZCB0aGUgZm9sbG93aW5nIG1ham9yIHN0ZXBzOgoKMS4gTWVyZ2UgaW50byBhIHNpbmdsZSBzZXVyYXQKMi4gU2NvcmUgIGVhY2ggY2VsbCBmb3IgUyBhbmQgRzJNIGNlbGwgY3ljbGUgZWZmZWN0cyB0aGF0IGFyZSBpbmNsdWRlZCBpbiB0aGUgcmVncmVzc2lvbi9ub3JtYWxpemF0aW9uIHN0ZXBzLiBTZWUgYGBgY29kZS9jZWxsLWN5Y2xlLXRlc3RpbmcuUmBgYCBhbmQgQXByIDEsIDIwMjEgcHJlc2VudGF0aW9uIGZvciBkZXRhaWxzLiAKMy4gTm9ybWFsaXplRGF0YSwgRmluZFZhcmlhYmxlRmVhdHVyZXMsIFNjYWxlRGF0YQo0LiBSdW5QQ0EgZm9sbG93ZWQgYnkgRWxib3cgcGxvdCB0byBpZGVudGlmeSBpbXBvcnRhbnQgcHJpbmNpcGFsIGNvbXBvbmVudHMKICAgIC0gIVtdKGRhdGEvcGxvdHMvcGNhLXNjYXR0ZXJwbG90cy5wbmcpCiAgICAtICFbXShkYXRhL3Bsb3RzL2VsYm93LnBuZykKNS4gUnVuVU1BUCBmb2xsd2VkIGJ5IERpbVBsb3QgCiAgICAtICFbXShkYXRhL3Bsb3RzL3VtYXAtYnktc2FtcGxlLnBuZykKNi4gSWRlbnRpZnkgb3B0aW1hbCBjbHVzdGVyIHJlc29sdXRpb24gdXNpbmcgY2x1c3RyZWUKICAgIC0gIVtdKGRhdGEvcGxvdHMvY2x1c3RyZWUtcGxvdF9sb3ctZW5kLnBuZykKICAgIC0gIVtdKGRhdGEvcGxvdHMvdW1hcC0wLjAzLnBuZykKNy4gT3V0cHV0IGZyb20gdGhpcyBtYWluIHByb2Nlc3NpbmcgaXMgc3RvcmVkIGFzIGBgYG9iamVjdHMvZmlsdGVyZWQtbWVyZ2VkLXVtYXAuUkRTYGBgCgojIyBEaWZmZXJlbnRpYWwgZXhwcmVzc2lvbgoKT25jZSBhbiBvcHRpbWFsIFNldXJhdCByZXNvbHV0aW9uIGhhZCBiZWVuIHNlbGVjdGVkICgwLjAzKSwgd2UgcmFuIGRpZmZlcmVudGlhbCBnZW5lIGV4cHJlc3Npb24gYW5hbHlzaXMgaW4gU2V1cmF0IHVzaW5nIHRoZSBGaW5kTWFya2VycyBmdW5jdGlvbiBpbiBTZXVyYXQuIFRoaXMgd2FzIHBlcmZvcm1lZCBmb3IgZWFjaCBjbHVzdGVyIGluIGEgY2x1c3Rlci12cy1hbGwgY29udHJhc3QgbW9kZWwuIFNpbmNlIGEgbGlzdCBvZiB0YXJnZXRlZCBnZW5lcyB3YXMgbm90IGV4cGxpY2l0bHkgcHJvdmlkZWQgd2UgcmVwb3J0IHRoZSB0b3AgMjAgZ2VuZXMgcGVyIGNsdXN0ZXIuIAoKYGBge2Jhc2h9CmxzIGRhdGEvcGxvdHMvZGV4LXRvcC1kb3RwbG90KgpgYGAKCiMjIEdlbmVyYWwgZW5yaWNobWVudCBhbmFseXNpcwoKV2UgZm9sbG93ZWQtdXAgdGhlIERHRSBhbmFseXNpcyB3aXRoIG92ZXItcmVwcmVzZW50YXRpb24gYW5hbHlzaXMgdXNpbmcgbXNpZ2RiIGFuZCBjbHVzdGVycHJvZmlsZXIgaW4gUiBleHBsb3JpbmcgdGhlIEdPIGdlbmUgc2V0cyBhbmQgS0VHRy4gVGhpcyB3b3JrIHdhcyBkZWZpbmVkIGJ5IHRoZSBgYGBjb2RlLzA2LWVucmljaHIuUmBgYCBzY3JpcHQgYW5kIGluY2x1ZGVzIG1zaWdkYiBjYXRlZ29yaWVzICJLRUdHIiwgIkM1IihHbyB0ZXJtcykgYXMgd2VsbCBhcyBtb2R1bGVzIGRlZmluZWQgZm9yIHRoZSBpUFNDIGNsdXN0ZXIgcHJvZmlsZXIgdG9vbCBhdCBOQ0FUcy4gUmVzdWx0cyBhcmUgc3VtbWFyaXplZCBvbiB0aGUgYGBgZGF0YS90YWJsZS9lbnJpY2hlZC1zZXRzLnRzdmBgYAoKCmBgYHtyfQpyZWFkX3RzdigiZGF0YS90YWJsZXMvZW5yaWNoZWQtc2V0cy50c3YiLCBjb2xfdHlwZXMgPSBjb2xzKAogIGNsdXN0ZXIgPSBjb2xfZG91YmxlKCksCiAgaGl0cyA9IGNvbF9kb3VibGUoKSwKICBJRCA9IGNvbF9jaGFyYWN0ZXIoKSwKICBEZXNjcmlwdGlvbiA9IGNvbF9jaGFyYWN0ZXIoKSwKICBHZW5lUmF0aW8gPSBjb2xfY2hhcmFjdGVyKCksCiAgQmdSYXRpbyA9IGNvbF9jaGFyYWN0ZXIoKSwKICBwdmFsdWUgPSBjb2xfZG91YmxlKCksCiAgcC5hZGp1c3QgPSBjb2xfZG91YmxlKCksCiAgcXZhbHVlID0gY29sX2RvdWJsZSgpLAogIGdlbmVJRCA9IGNvbF9jaGFyYWN0ZXIoKSwKICBDb3VudCA9IGNvbF9kb3VibGUoKSApKSAlPiUgCiAgc2xpY2UoMToxMCkgJT4lIAogIHNlbGVjdCgtZ2VuZUlEKQpgYGAKCmBgYHtiYXNofQpscyBkYXRhL3Bsb3RzL2dvKgpscyBkYXRhL3Bsb3RzL2tlZ2cqCmBgYAoKCiMjIE1vZHVsZSBjb252ZXJzaW9uIGFuZCBzY29yaW5nCgpMYXN0bHksIHRvIGJldHRlciB1bmRlcnN0YW5kIHRoZSBpZGVudGl0eSBvciBjZWxsIHR5cGUgZm9yIGVhY2ggY2x1c3Rlciwgd2UgcmFuIFNldXJhdOKAmXMgQWRkTW9kdWxlU2NvcmUgZnVuY3Rpb24sIHVzaW5nIE5DQVRT4oCZIGxpc3Qgb2Yga25vd24gY2VsbCBtYXJrZXJzIGZyb20gYSBwcmV2aW91c2x5IGNyZWF0ZWQgaVBTQyBwcm9maWxlciBmb3IgZWFjaCBjZWxsIHNlcGFyYXRpb24gYXBwcm9hY2guIFRoZSBBZGRNb2R1bGVTY29yZSBjYWxjdWxhdGVzIHRoZSBhdmVyYWdlIGV4cHJlc3Npb24gZm9yIGVhY2ggY2x1c3RlciBzdWJ0cmFjdGVkIGJ5IHRoZSBhZ2dyZWdhdGVkIGV4cHJlc3Npb24gb2YgY29udHJvbCBmZWF0dXJlIHNldHMuIFBvc2l0aXZlIGV4cHJlc3Npb24gbGV2ZWxzIGluZGljYXRlIGEgaGlnaGVyIGV4cHJlc3Npb24gbGV2ZWwgdGhhbiByYW5kb20uIFdlIHdpbGwgdXNlIHRoZSBleHByZXNzaW9uIGxldmVscyB0byBicm9hZGx5IGFzc2lnbiBlYWNoIGNsdXN0ZXIgdG8gcG90ZW50aWFsIGlkZW50aXRpZXMgKGNlbGwgdHlwZSkuIAoKYGBge2Jhc2h9CmxzIGRhdGEvcGxvdHMvaXBzYyoKYGBgCgojIyBUcmFqZWN0b3J5IGluZmVyZW5jZQoKTGFzdGx5LCB3ZSByYW4gU2xpbmdzaG90IGZvciBzaW5nbGUtY2VsbCB0cmFqZWN0b3J5IGFuYWx5c2lzLiBUaGUgZ29hbCBvZiBzbGluZ3Nob3QgaXMgdG8gdXNlIGNsdXN0ZXJzIG9mIGNlbGxzIHRvIHVuY292ZXIgZ2xvYmFsIHN0cnVjdHVyZSBhbmQgY29udmVydCB0aGVzZSB0byBwc2V1ZG90aW1lLiBUbyBhY2NvbXBsaXNoIHRoaXMgd29yayB3ZSB1dGlsaXplZCB0aGUgKmR5bnZlcnNlKiBzZXQgb2YgUi1wYWNrYWdlcyBpbiBjb25qdW5jdGlvbiB3aXRoIHByb3ZpZGVkIGNvZGUgZnJvbSBDbGFpcmUgTWFsbGV5IHRvIHJ1biBTbGluZ3Nob3QgYW5kIGV4dHJhY3QgcHNldWRvdGltZSBtZXRyaWNzLiAKClRoaXMgYW5hbHlzaXMgeWllbGRlZCBzb21lIHByb2R1Y3RpdmUgZmluZGluZ3MgYWNyb3NzIHRoZSBhbm5vdGF0ZWQgdW1hcCBjbHVzdGVycy4gVGhpcyByb3VnaGx5IGZvbGxvd2VkIGEgdHJhamVjdG9yeSBhbG9uZyBuZXVyb25hbCBwcmVjdXJzb3JzIChjbHVzdGVyIDEpLCBnbGlhbC9hc3RyYWwvU0dDIGNlbGxzIChjbHVzdGVyIDAsIHRoZSBsYXJnZXN0KSBhbmQgc3BsaXRzIGludG8gc2V2ZXJhbCB0eXBlcyBvZiBtYXR1cmluZyBub2NpY2VwdG9ycyAoY2x1c3RlciA1KSBhbmQgbGlrZWx5IGFsdGVybmF0aXZlIGRldmVsb3BtZW50YWwgbmV1cm9uYWwgY2VsbCB0eXBlcyAoY2x1c3RlcnMgMyw2KSAKCiFbXShkYXRhL3Bsb3RzL3RpLXVtYXAtY2x1c3Rlci5wbmcpCldoZW4gYW4gdW5zdXBlcnZpc2VkIHBzZXVkb3RpbWUgZXN0aW1hdGlvbiBpcyBwbG90dGVkIG9uIHRoZXNlIGNlbGxzIHdlIHNlZSBhIG5hdHVyYWwgcHJvZ3Jlc3Npb24uCgohW10oZGF0YS9wbG90cy90aS11bWFwLXBzZXVkb3RpbWUucG5nKQoKCiMjIFBzZXVkb3R5cGUtYmFzZWQgZGlmZmVyZW50aWFsIG1vZGVsaW5nCgpBZnRlciBTbGluZ3Nob3Qgd2FzIHJ1biwgd2UgZXhwbG9yZWQgdGVtcG9yYWxseSBleHByZXNzZWQgZ2VuZXMgdXNpbmcgdGhlIHRyYWRlU2VxIHBhY2thZ2UuIEZvciBlYWNoIGdlbmUsIHdlIGZpdCBhIGdlbmVyYWwgYWRkaXRpdmUgbW9kZWwgKEdBTSkgdXNpbmcgYSBuZWdhdGl2ZSBiaW5vbWlhbCBub2lzZSBkaXN0cmlidXRpb24gdG8gbW9kZWwgcmVsYXRpb25zaGlwcyBiZXR3ZWVuIGdlbmUgZXhwcmVzc2lvbiBhbmQgcHNldWRvdGltZS4gQWZ0ZXIgcnVubmluZyB0aGUgR0FNIG1vZGVsLCB3ZSB0ZXN0ZWQgZm9yIHNpZ25pZmljYW50IGFzc29jaWF0aW9ucyBiZXR3ZWVuIGV4cHJlc3Npb24gYW5kIHBzZXVkb3RpbWUgdXNpbmcgdGhlIGFzc29jaWF0aW9uVGVzdC4gCg==